package hos.java.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import hos.java.compat.CalendarConvert;

/**
 * <p>Title: StringUtils </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2022/7/2 15:47
 */
public class StringUtils {

    /**
     * 下划线
     */
    private static final char SEPARATOR = '_';

    /**
     * Returns true if a and b are equal, including if they are both null.
     * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if
     * both the arguments were instances of String.</i></p>
     *
     * @param a first CharSequence to check
     * @param b second CharSequence to check
     * @return true if a and b are equal
     */
    public static boolean equals(CharSequence a, CharSequence b) {
        return AnyUtils.equals(a, b);
    }

    /**
     * Returns true if the string is null or 0-length.
     *
     * @param str the string to be examined
     * @return true if str is null or zero length
     */
    public static boolean isEmpty(CharSequence str) {
        return str == null || str.length() == 0 || equals("null", str) || equals("NULL", str) || equals("Null", str);
    }

    public static boolean isNotEmpty(CharSequence str) {
        return !isEmpty(str);
    }

    public static boolean contains(CharSequence seq, int searchChar) {
        if (isEmpty(seq)) {
            return false;
        } else {
            return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
        }
    }

    //<editor-fold desc="IS">

    /**
     * 是否为浮点数, 无论Float或者Double
     *
     * @return Boolean
     * @receiver String
     */
    public static Boolean isDouble(CharSequence target) {
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(target).matches();
    }

    /**
     * 是否为整数
     *
     * @return Boolean
     * @receiver String
     */
    public static Boolean isInteger(CharSequence target) {
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(target).matches();
    }


    /**
     * 是否是数字
     *
     * @return Boolean
     * @receiver String
     */
    public static Boolean isNumber(CharSequence target) {
        if (".".contentEquals(target)) {
            return false;
        }
        return isDouble(target) || isInteger(target);
    }
    //</editor-fold>


    //<editor-fold desc="Format">

    /**
     * 数字转成百分比形式 (1 = 100%) 默认3位数
     *
     * @param fraction Boolean
     * @return String
     * @receiver String
     */
    public static String percent(String target, Boolean fraction) {
        return percent(target, fraction, 2);
    }

    /**
     * 数字转成百分比形式 (1 = 100%) 默认3位数
     *
     * @param fraction     Boolean
     * @param decimalCount Int
     * @return String
     * @receiver String
     */
    public static String percent(String target, Boolean fraction, int decimalCount) {
        if (!isNumber(target)) {
            return "";
        }
        NumberFormat numberFormat = NumberFormat.getPercentInstance();
        if (fraction) {
            numberFormat.setMaximumFractionDigits(decimalCount);
            numberFormat.setMinimumFractionDigits(decimalCount);
        }
        try {
            return numberFormat.format(target);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 将字符串数字进行格式化 #.##
     *
     * @param target 目标值
     * @return 格式化后的字符串
     */
    public static String format(CharSequence target) {
        return format(target, "#.##");
    }

    /**
     * 将字符串数字进行格式化
     *
     * @param target 目标值
     * @param format 格式化样式
     * @return 格式化后的字符串
     */
    public static String format(CharSequence target, String format) {
        try {
            String orEmpty = AnyUtils.empty(target);
            DecimalFormat numberFormat = new DecimalFormat(format);
            String result = numberFormat.format(orEmpty);
            if (AnyUtils.empty(result).isEmpty()) {
                return "0";
            }
            if (result.equals(".00")) {
                return "0";
            }
            if (result.contains(".") && ".".equals(result.substring(0, 1))) {
                return "0" + result;
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return "0";
        }
    }


    public static String formatFileSize(long size) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (size == 0) {
            return wrongSize;
        }
        if (size < 1024) {
            fileSizeString = df.format((double) size) + "B";
        } else if (size < 1048576) {
            fileSizeString = df.format((double) size / 1024) + "KB";
        } else if (size < 1073741824) {
            fileSizeString = df.format((double) size / 1024) + "MB";
        } else if (size < 1099511627776L) {
            fileSizeString = df.format((double) size / 1073741824) + "GB";
        } else if (size < 1125899906842624L) {
            fileSizeString = df.format((double) size / 1099511627776L) + "TB";
        } else {
            fileSizeString = df.format((double) size / 1125899906842624L) + "PB";
        }
        return fileSizeString;
    }

    public static String formatFileSize(String file) {
        return formatFileSize(fileSize(file));
    }

    public static String formatFileSize(File file) {
        return formatFileSize(fileSize(file));
    }
    //</editor-fold>


    //<editor-fold desc="Split">

    /**
     * 根据指定的字符把源字符串分割成一个list
     *
     * @param src     处理的字符串
     * @param pattern 分割字符串
     * @return 处理后的list
     */
    public static List<String> splitList(String src, String pattern) {
        List<String> list = new ArrayList<>();
        if (AnyUtils.toNull(src) != null) {
            String[] tt = src.split(pattern);
            list.addAll(Arrays.asList(tt));
        }
        return list;
    }

    /**
     * 获取已,隔开的第一个
     */
    public static String splitFirst(String target, String pattern) {
        if (AnyUtils.toNull(target) == null) {
            return "";
        }
        if (target.contains(pattern)) {
            return target.split(pattern)[0];
        }
        return target;
    }
    //</editor-fold>

    /**
     * 截取字符串左侧指定长度的字符串
     *
     * @param input 输入字符串
     * @param count 截取长度
     * @return 截取字符串
     */
    public static String left(String input, int count) {
        if (AnyUtils.toNull(input) == null) {
            return "";
        }
        count = Math.min(count, input.length());
        return input.substring(0, count);
    }

    /**
     * 截取字符串右侧指定长度的字符串
     *
     * @param input 输入字符串
     * @param count 截取长度
     * @return 截取字符串
     * Summary 其他编码的有待测试
     */
    public static String right(String input, int count) {
        if (AnyUtils.toNull(input) == null) {
            return "";
        }
        count = Math.min(count, input.length());
        return input.substring(input.length() - count, input.length());
    }

    public static final Pattern PATTER_BLANK_CODE = Pattern.compile("\\s*|\t|\r|\n");

    /**
     * 页面中去除字符串中的空格、回车、换行符、制表符
     *
     * @param str 需要处理的字符串
     */
    public static String replaceBlank(CharSequence str) {
        if (str != null) {
            Matcher m = PATTER_BLANK_CODE.matcher(str);
            return m.replaceAll("");
        }
        return "";
    }

    public static String deleteEndZero(String value) {
        value = AnyUtils.empty(value);
        if (value.indexOf(".") > 0) {
            value = value.replaceAll("0+?$", "");//去掉多余的0
            value = value.replaceAll("[.]$", "");//如最后一位是.则去掉
        }
        return value;
    }


    //<editor-fold desc="Html">

    public static String url(CharSequence target) {
        return url(target, false, null);
    }

    /**
     * 对接连接地址 进行处理
     *
     * @param target  目标地址
     * @param isHttps true 是https
     * @param ip      地址
     * @return
     */
    public static String url(CharSequence target, boolean isHttps, String ip) {
        String url = AnyUtils.empty(target);
        if (url.isEmpty()) {
            return "";
        }
        if (url.contains("http://")) {
            return url;
        } else if (url.contains("https://")) {
            return url;
        } else {
            if (AnyUtils.empty(ip).isEmpty()) {
                if (isHttps) {
                    return "https://" + url;
                }
                return "http://" + url;
            }
            if (ip.startsWith("http")) {
                return ip + url;
            }
            if (isHttps) {
                return "https://" + ip + url;
            }
            return "http://" + ip + url;
        }
    }

    /**
     * 去除html中的空格
     *
     * @param html 目标
     */

    public static String htmlTrim(String html) {
        if (AnyUtils.toNull(html) == null) {
            return "";
        }
        if (html.contains("&nbsp;")) {
            html = html.replaceAll("&nbsp;", " ");
        }
        return html.trim();
    }

    /**
     * 从连接地址中获取Url
     *
     * @param url 访问地址
     */
    public static String url(String url) {
        if (AnyUtils.toNull(url) == null) {
            return "";
        }
        if (url.contains("?")) {
            return url.split("\\?")[0];
        }
        return url;
    }


    public static String trim(String target) {
        if (AnyUtils.toNull(target) == null) {
            return "";
        }
        return target.replaceAll("\n", "")
                .replaceAll("\t", "")
                .replaceAll("\r", "").trim();
    }

    /**
     * 从连接地址中获取Url
     *
     * @param url 访问地址
     */
    public static Map<String, String> urlParams(String url) {
        Map<String, String> map = new HashMap<>();
        if (AnyUtils.toNull(url) == null) {
            return map;
        }
        if (url.contains("?")) {
            String paramStr = url.split("\\?")[1];
            if (paramStr.contains("&")) {
                String[] params = paramStr.split("&");
                for (String param : params) {
                    if (param.contains("=")) {
                        String[] paramSplit = param.split("=");
                        if (paramSplit.length == 1) {
                            map.put(paramSplit[0], null);
                        } else {
                            map.put(paramSplit[0], paramSplit[1]);
                        }
                    }
                }
            } else {
                if (paramStr.contains("=")) {
                    String[] paramSplit = paramStr.split("=");
                    if (paramSplit.length == 1) {
                        map.put(paramSplit[0], null);
                    } else {
                        map.put(paramSplit[0], paramSplit[1]);
                    }
                }
            }
        } else {
            if (url.contains("&")) {
                String[] params = url.split("&");
                for (String param : params) {
                    if (param.contains("=")) {
                        String[] paramSplit = param.split("=");
                        if (paramSplit.length == 1) {
                            map.put(paramSplit[0], null);
                        } else {
                            map.put(paramSplit[0], paramSplit[1]);
                        }
                    }
                }
            } else {
                if (url.contains("=")) {
                    String[] paramSplit = url.split("=");
                    if (paramSplit.length == 1) {
                        map.put(paramSplit[0], null);
                    } else {
                        map.put(paramSplit[0], paramSplit[1]);
                    }
                }
            }
        }
        return map;
    }
    //</editor-fold>

    /**
     * 下划线转驼峰命名
     */
    public static String toUnderScoreCase(String s) {
        if (s == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            boolean nextUpperCase = true;
            if (i < (s.length() - 1)) {
                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
            }
            if ((i > 0) && Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR);
                }
                upperCase = true;
            } else {
                upperCase = false;
            }
            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }


    /**
     * 剔除返回xml中的类型
     *
     * @param body 处理目标
     * @return 返回值
     */
    public static String toSoap(CharSequence body) {
        return AnyUtils.empty(body).replaceAll("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
                .replaceAll("\n", "")
                .replaceAll("\t", "")
                .replaceAll("\r", "")
                .replaceAll("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
                .replaceAll("<boolean xmlns=\"http://tempuri.org/\">", "")
                .replaceAll("<long xmlns=\"http://tempuri.org/\">", "")
                .replaceAll("<double xmlns=\"http://tempuri.org/\">", "")
                .replaceAll("<int xmlns=\"http://tempuri.org/\">", "")
                .replaceAll("<string xmlns=\"http://tempuri.org/\">", "")
                .replaceAll("</string>", "")
                .replaceAll("</int>", "")
                .replaceAll("</double>", "")
                .replaceAll("</long>", "")
                .replaceAll("</boolean>", "")
                .replaceAll("</xml>", "")
                .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
                .replace("\n", "")
                .replace("\t", "")
                .replace("\r", "")
                .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
                .replace("<boolean xmlns=\"http://tempuri.org/\">", "")
                .replace("<long xmlns=\"http://tempuri.org/\">", "")
                .replace("<double xmlns=\"http://tempuri.org/\">", "")
                .replace("<int xmlns=\"http://tempuri.org/\">", "")
                .replace("<string xmlns=\"http://tempuri.org/\">", "")
                .replace("</string>", "")
                .replace("</double>", "")
                .replace("</long>", "")
                .replace("</boolean>", "")
                .replace("</xml>", "").trim();
    }

    /**
     * Return whether the string is null or white space.
     *
     * @param s The string.
     * @return {@code true}: yes<br> {@code false}: no
     */
    public static boolean isSpace(final String s) {
        if (s == null) return true;
        for (int i = 0, len = s.length(); i < len; ++i) {
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }


    //<editor-fold desc="Time">
    public static String timeNull(CharSequence target) {
        return time(target, null);
    }

    public static String time(CharSequence target) {
        return time(target, "");
    }

    public static String time(CharSequence target, String defaultNull) {
        Object orNull = AnyUtils.toNull(target);
        if (orNull == null) {
            return defaultNull;
        }
        return CalendarConvert.toEmpty(AnyUtils.empty(target));
    }

    public static Calendar calendar(CharSequence target, Calendar calendar) {
        String time = timeNull(target);
        if (time == null) {
            return calendar;
        }
        return CalendarConvert.string2Calendar(time);
    }

    public static Calendar calendar(CharSequence target) {
        return calendar(target, new GregorianCalendar());
    }
    //</editor-fold>

    //<editor-fold desc="Length">
    public static int fontLength(String target) {
        String orStringEmpty = AnyUtils.empty(target).replace("[^\\x00-\\xff]", "**");
        int strLength = 0;
        String chinese = "[\u0391-\uFFE5]";
        /* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */
        for (int i = 0; i < orStringEmpty.length(); i++) {
            /* 从字符串中获取一个字符 */
            String temp = orStringEmpty.substring(i, i + 1);
            /* 判断是否为中文字符 */
            if (temp.matches(chinese)) {
                /* 中文字符长度为2 */
                strLength += 2;
            } else {
                /* 其他字符长度为1 */
                strLength += 1;
            }
        }
        return strLength;
    }

    public static String addLength(int allLength) {
        StringBuilder newString = new StringBuilder();
        for (int i = 0; i < (allLength); i++) {
            newString.append(" ");
        }
        return newString.toString();
    }

    public static String addLength(String target, int allLength) {
        String targetEmpty = AnyUtils.empty(target);
        int spaceLength = (allLength - fontLength(targetEmpty)) - 1;
        StringBuilder newString = new StringBuilder(" " + targetEmpty);
        for (int i = 0; i < spaceLength; i++) {
            newString.append(" ");
        }
        return newString.toString();
    }

    @SuppressWarnings("StringConcatenationInLoop")
    public static String addLengthCenter(String target, int allLength) {
        String targetEmpty = AnyUtils.empty(target);
        int spaceLength = (allLength - fontLength(targetEmpty)) / 2;
        for (int i = 0; i < spaceLength; i++) {
            targetEmpty = " " + targetEmpty + " ";
        }
        return targetEmpty;
    }
    //</editor-fold>


    public static long fileSize(String file) {
        return fileSize(new File(file));
    }

    public static long fileSize(File file) {
        long length = file.length();
        if (length != 0) {
            return length;
        }
        FileChannel channel = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            channel = fileInputStream.getChannel();
            return channel.size();
        } catch (IOException ignored) {
            return 0;
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException ignored) {

                }
            }
        }
    }
}
